package com.next.core.util;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 注解类型 + 对象 
 * @author fei.wang
 *
 * @param <T>
 */
public class AnnotationObjectMap<T>
{
    private static Logger LOGGER = LoggerFactory.getLogger(AnnotationClazzMap.class);

    private Class<?> keyType;
    
    protected final Map<Object, T> map = new HashMap<Object, T>();

    public AnnotationObjectMap()
    {
        this(String.class);
    }
    
    public AnnotationObjectMap(Class<?> keyType)
    {
        this.keyType = keyType;
    }
    
    @SuppressWarnings("unchecked")
    public boolean load(String scriptPackage)
    {
        List<Class<?>> allClasses = ClassUtil.getClasses(scriptPackage);
        for (Class<?> clazz : allClasses)
        {
            try
            {
            	GenericAnnotation cmd = clazz.getAnnotation(GenericAnnotation.class);
                if (cmd == null)
                    continue;

                Object key = getKey(cmd);
                
                if (map.containsKey(key))
                {
                    String name = map.get(cmd.type()).getClass().getName();
                    LOGGER.error("cmd code error, code : " + key + " exist :" + name
                            + ", new : " + clazz.getName());
                    return false;
                }

                map.put(key, (T) clazz.newInstance());
            }
            catch (Exception e)
            {
                LOGGER.error("load command fail, command name : " + clazz.getName(), e);
            }
        }

        return true;
    }
    
    private Object getKey(GenericAnnotation cmd)
    {
        if (keyType == Integer.class)
        {
            return cmd.code();
        }
        else if (keyType == String.class) 
        {
            return cmd.type();
        }
        
        return null;
    }

    public T get(Object type)
    {
        if (map.containsKey(type))
            return map.get(type);

        return null;
    }
    
    public Map<Object, T> getInner()
    {
    	return map;
    }
}
